#!/usr/bin/env python
#
# Copyright 2009 Facebook
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Simplified chat demo for websockets.

Authentication, error handling, etc are left as an exercise for the reader :)
"""


import tornado.web

import logging
import tornado.escape
import tornado.ioloop
import tornado.options
import tornado.autoreload
import tornado.web
import tornado.websocket
import os.path
import uuid
import json
import random
import subprocess
import mimetypes
import sqlite3

from tornado.options import define, options

define("port", default=80, help="run on the given port", type=int)
table_name = 'webscripts'


 
def _execute(query):
        dbPath = bin_dir = os.path.join(os.getcwd(), "db", "webscripts.db")
        connection = sqlite3.connect(dbPath)
        cursorobj = connection.cursor()
        try:
                cursorobj.execute(query)
                result = cursorobj.fetchall()
                connection.commit()
        except Exception:
                print "Unable to execute query into database"
                print "Exception" + str(Exception)
                print "Query: " + query
                raise
        connection.close()
        return result

class Application(tornado.web.Application):
    def __init__(self):
        handlers = [
            (r"/", MainHandler),
            (r"/script/(.*)", ScriptHandler),

            (r"/chatsocket", ChatSocketHandler),


            (r"/api/command", APICommandHandler),
            (r"/postFile", FileUploadHandler),
            (r"/api/save", APISaveHandler),
            (r"/api/remove", APIRemoveHandler),
            (r"/api", APIHandler),
            (r"/file", FileServerHander)
        ]
        settings = dict(
            cookie_secret="__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__",
            template_path=os.path.join(os.path.dirname(__file__), "templates"),
            static_path=os.path.join(os.path.dirname(__file__), "static"),
            #xsrf_cookies=True,
            debug=True
        )
        tornado.web.Application.__init__(self, handlers, **settings)


class MainHandler(tornado.web.RequestHandler):
    def get(self):
        query = 'select * from ' + table_name
        data = _execute(query)
        self.render("index.html", 
            scripts= data
            )
class ScriptHandler(tornado.web.RequestHandler):
    def get(self, script_name):
        query = 'select * from ' + table_name + ' where script_name = "%s" ' %(script_name)
        data = _execute(query)

        if len(data) > 0:
            data = data[0]
        else:
            raise tornado.web.HTTPError(404)
 

        self.render("script.html", 
            scriptname= script_name,
            script= data,
            )


class APISaveHandler(tornado.web.RequestHandler):
    def get(self):
        self.post()
    def post(self):
        script_name = self.get_argument("script_name", default=None, strip=False)
        file_input = self.get_argument("file_input", default=None, strip=False)
        description = self.get_argument("description", default=None, strip=False)
        image = self.get_argument("image", default=None, strip=False)

        table_query = ''.join(['create table if not exists ', table_name, 
        ''' 
        (
            script_name String, 
            file_input String, 
            description String,
            image String,
            parameters String,
            id INTEGER PRIMARY KEY AUTOINCREMENT
        )'''])
        _execute(table_query)

        query = ''' insert into ''' + table_name + ''' (script_name, file_input, description, image) values ('%s', '%s', '%s', '%s') ''' %(script_name, file_input, description, image);
        data = _execute(query)

        return self.write(str(data))

class APIRemoveHandler(tornado.web.RequestHandler):
    def get(self):
        self.post()
    def post(self):
        id = self.get_argument("id", default=None, strip=False)

        if id:
            query = 'delete from ' + table_name + ' where id = "%s" ' %(id)
            data = _execute(query)
            return self.write(str(data))

        return self.write(str(data))

class APIHandler(tornado.web.RequestHandler):
    def get(self):
        self.post()
    def post(self):

        query = 'select * from ' + table_name
        data = _execute(query)

        # script_name = self.get_argument("script_name", default=None, strip=False)
        # file_input = self.get_argument("file_input", default=False, strip=False)
        # description = self.get_argument("description", default=None, strip=False)

        # data = {
        #     'script_name': script_name,
        #     'file_input': file_input,
        #     'description': description
        # }
        return self.write(json.dumps(data))


class FileServerHander(tornado.web.RequestHandler):
    def get(self):
        #Todo Delete?
        id = self.get_argument('id')
        if id:
            #self.set_header('Content-Type', mimetypes.guess_type(id))


            bin_dir = os.path.join(os.getcwd(), "bin", id)

            from os import listdir
            from os.path import isfile, join
            files = [ f for f in listdir(bin_dir) if isfile(join(bin_dir,f)) ]

            for f in files:
                output_file_path = os.path.join(bin_dir, f)

                self.set_header ('Content-Disposition', 'attachment; filename='+f+'')

                with open(output_file_path, 'rb') as f:
                    while 1:
                        data = f.read(16384) # or some other nice-sized chunk
                        if not data: break
                        self.write(data)
        self.finish()


class APICommandHandler(tornado.web.RequestHandler):
    def post(self):


        script_name = self.get_argument("script_name", default=None, strip=False)

        if not script_name:
            raise tornado.web.HTTPError(400)

        query = 'select * from ' + table_name + ' where script_name = "%s" ' %(script_name)
        data = _execute(query)

        if len(data) > 0:
            pass
        else:
             tornado.web.HTTPError(400)


        input_script = data[0][0] + '.py'



        #Upload the file into the uploads directory

        f = self.request.files['file'][0]
        original_fname = f['filename']
        extension = os.path.splitext(original_fname)[1]
        operation_uuid = str(uuid.uuid4())
        final_filename= operation_uuid+extension

        file_path =  os.path.join(os.getcwd(), "uploads", final_filename)

        output_file = open(file_path, 'wb')
        for a in f['body']:
            output_file.write(a)
        output_file.close()

        #self.finish("file" + final_filename + " is uploaded")
        #logging.info(f['body'])
        #logging.info("file" + final_filename + " is uploaded")


        #Determine Script to use
        #Use script
        input_file = final_filename
        input_file = os.path.join(os.getcwd(), "uploads", input_file)
        input_script = os.path.join(os.getcwd(), "scripts", input_script)
        bin_dir = os.path.join(os.getcwd(), "bin", operation_uuid) #TODO make folder with id .. grab everything in that folder

        if not os.path.exists(bin_dir):
            os.makedirs(bin_dir)

        command = "python " + '"' + input_script + '"' + " " + '"' + input_file + '"'
        logging.info(command)


        output = []
        p =subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=bin_dir)
        for line in p.stdout.readlines():
            logging.info(line)
            output.append(line)
        retval = p.wait()



        #Return File
        
        # with open(output_file_path, 'rb') as f:
        #     while 1:
        #         data = f.read(16384) # or some other nice-sized chunk
        #         if not data: break
        #         self.write(data)
        # self.finish()


        from os import listdir
        from os.path import isfile, join
        files = [ f for f in listdir(bin_dir) if isfile(join(bin_dir,f)) ]

        logging.info("files", files)

        data = {
            'operation_uuid': operation_uuid,
            'number_of_files': len(files),
            'output': output
        }
        return self.write(json.dumps(data))
        
class FileUploadHandler(tornado.web.RequestHandler):
    def post(self):


        script_name = self.get_argument("script_name", default=None, strip=False)

        if not script_name:
            raise tornado.web.HTTPError(400)

        query = 'select * from ' + table_name + ' where script_name = "%s" ' %(script_name)
        data = _execute(query)

        if len(data) > 0:
            pass
        else:
             tornado.web.HTTPError(400)


        input_script = data[0][0] + '.py'



        #Upload the file into the uploads directory

        f = self.request.files['file'][0]
        original_fname = f['filename']
        extension = os.path.splitext(original_fname)[1]
        operation_uuid = str(uuid.uuid4())
        final_filename= operation_uuid+extension

        file_path =  os.path.join(os.getcwd(), "uploads", final_filename)

        output_file = open(file_path, 'wb')
        for a in f['body']:
            output_file.write(a)
        output_file.close()

        #self.finish("file" + final_filename + " is uploaded")
        #logging.info(f['body'])
        #logging.info("file" + final_filename + " is uploaded")


        #Determine Script to use
        #Use script
        input_file = final_filename
        input_file = os.path.join(os.getcwd(), "uploads", input_file)
        input_script = os.path.join(os.getcwd(), "scripts", input_script)
        bin_dir = os.path.join(os.getcwd(), "bin", operation_uuid) #TODO make folder with id .. grab everything in that folder

        if not os.path.exists(bin_dir):
            os.makedirs(bin_dir)

        command = "python " + '"' + input_script + '"' + " " + '"' + input_file + '"'
        logging.info(command)
        logging.info(bin_dir)

        output = []
        p =subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=bin_dir)
        for line in p.stdout.readlines():
            logging.info(line)
            output.append(line + "\n")
        retval = p.wait()



        #Return File
        
        # with open(output_file_path, 'rb') as f:
        #     while 1:
        #         data = f.read(16384) # or some other nice-sized chunk
        #         if not data: break
        #         self.write(data)
        # self.finish()


        from os import listdir
        from os.path import isfile, join
        files = [ f for f in listdir(bin_dir) if isfile(join(bin_dir,f)) ]

        logging.info("files", files)

        data = {
            'operation_uuid': operation_uuid,
            'number_of_files': len(files),
            'output': output
        }
        return self.write(json.dumps(data))

class ChatSocketHandler(tornado.websocket.WebSocketHandler):
    waiters = set()
    cache = []
    cache_size = 200

    def allow_draft76(self):
        # for iOS 5.0 Safari
        return True

    def open(self):
        ChatSocketHandler.waiters.add(self)

    def on_close(self):
        ChatSocketHandler.waiters.remove(self)

    @classmethod
    def update_cache(cls, chat):
        cls.cache.append(chat)
        if len(cls.cache) > cls.cache_size:
            cls.cache = cls.cache[-cls.cache_size:]

    @classmethod
    def send_updates(cls, chat):
        logging.info("sending message to %d waiters", len(cls.waiters))
        for waiter in cls.waiters:
            try:
                waiter.write_message(chat)
            except:
                logging.error("Error sending message", exc_info=True)

    def on_message(self, message):
        logging.info("got message %r", message)
        parsed = tornado.escape.json_decode(message)
        chat = {
            "id": str(uuid.uuid4()),
            "body": parsed["body"],
            }
        chat["html"] = tornado.escape.to_basestring(
            self.render_string("message.html", message=chat))

        ChatSocketHandler.update_cache(chat)
        ChatSocketHandler.send_updates(chat)


def main():
    tornado.options.parse_command_line()
    app = Application()
    app.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()
    #tornado.autoreload.start(io_loop=None, check_time=500)

if __name__ == "__main__":
    main()
